#!/usr/bin/python

# Import ###############################################################
import sys
import getopt
import feedparser
import hashlib
from pysqlite2 import dbapi2 as sqlite
########################################################################

# Define Globals #######################################################
# Setup program name and version
program_name    = 'phlyAggregator'
version_major   = 0
version_minor   = 2
version_state   = '-alpha'
version         = '%d.%d%s'                              % (version_major, version_minor, version_state)
version_string  = '%s %s (http://www.phly-project.org)'  % (program_name, version)

# Config dir
config_dir      = '/home/phalax/.config/phly/%s'         % program_name

# Setup database
database        = '%s/%s.db'                             % (config_dir, program_name)
connect         = sqlite.connect(database)
cursor          = connect.cursor()

# Other globals
verbose         = False
fake            = False
action          = ''
feed_to_catchup = ''
########################################################################

# Prints the help and about screens. ###################################
def usage_screen(view = 'help', error_message = False):
    usage_text = '' # define usage_text    
    if view == 'about':
        usage_text += 'About:\t%s is a Podcast Aggregator.\n' % program_name
        usage_text += '\tIts only made to be a simple script.\n'
        usage_text += '\tUse at your own risk!\n'
        usage_text += '\tFor more info check:\n'
        usage_text += '\thttp://sites.google.com/site/phlyproject/\n'
        usage_text += '\thttp://code.google.com/p/phlyproject/\n'
    elif view == 'help' or view == 'error':
        if error_message != False:
            usage_text += colorize('error', error_message) + '\n\n'
        usage_text += 'Usage:\t%s[options] <actions>\n' % program_name
        usage_text += 'Options:\n'
        usage_text += '\t-a\t\tPrint the about screen\n'
        usage_text += '\t-c\t\tPrint errorcode list\n'
        usage_text += '\t-V\t\tPrint version\n'
        usage_text += '\t-h\t\tPrint this help screen\n'
        usage_text += '\t-f\t\tFake run\n'
        usage_text += '\t-v\t\tSet verbose output\n'
        usage_text += 'Actions:\n'
        usage_text += '\t--update\tUpdate feeds\n'
        usage_text += '\nExample: %s -v --update\n' % program_name
    elif view == 'codes':
        usage_text += '2: User error\n'
        usage_text += '5: Programmer error\n'
        
    print usage_text
########################################################################

# parse all the options
def parse_arguments():
    global action, fake, verbose, feed_to_catchup
    
    # Get arguments
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'acVhfv', ['update','catchup-all','catchup='])
    except getopt.GetoptError, err:
        usage_screen('error', srt(err))

    # Now parse the arguments
    for o, a in opts:                                                   # Walk throught all options and setup som stuff.
        if   o in '-v':
            verbose = True
        elif o in '-f':
            fake = True
        elif o in '--update':           # Action update
            action = 'update'
        elif o in '--catchup=':         # Action CatchUp=number
            action = 'catchup'
            feed_to_catchup = a
        elif o in '--catchup-all':      # Action CatchUp-all
            action = 'catchup'
            feed_to_catchup = 'all'
        elif o in '-h':
            usage_screen('help')
        elif o in '-a':
            usage_screen('about')
        elif o in '-c':
            usage_screen('codes')
        elif o == '-V':
            sys.exit()                                                  # Always printed
########################################################################

# The update procedure #################################################
def update_feeds():
    newInTotal = 0
    
    # Get feeds from database
    feeds = get_feed_list()
    
    # Walk through them
    for feedID, feedURL, feedTITLE in feeds:
        
        # Parse the feed
        pod = feedparser.parse(feedURL)
        
        # Feedback
        print '%s\t%s%s'          % (colorize('blue', 'Podcast:'), colorize('green', str(feedID)), colorize('green',  ', ' + pod.feed.title))
        if verbose == True:
            print '%s\t\t%s'    % (colorize('blue', 'Feed:'),    colorize('green',  feedURL))
            print '%s\t%s'      % (colorize('blue', 'Entries:'), colorize('number', len(pod.entries)))
                    
        # Go through all the entries(episodes)
        entry     = 0
        newInFeed = 0
        enclosure_count = 0
        while entry < len(pod.entries):
            # Setup episode variables
            #episode = pod.entries[i]
            episode_title       = pod.entries[entry].get('title',    'No Title')
            episode_published   = pod.entries[entry].get('date',     'No date')
            episode_description = pod.entries[entry].get('subtitle', 'No summary')
            if pod.entries[entry].has_key('enclosures'):
                # If has a file
                episode_url     = pod.entries[entry].enclosures[0].url
                episode_type    = pod.entries[entry].enclosures[0].type
                enclosure_count += 1
            else:
                episode_url = 'Not an episode.'

            # Generate md5 key for podacst
            # The feedTITLE is from database!! So the md5 dont change when they
            # change something in the name.
            md5key = hashlib.md5(feedTITLE + episode_published + episode_url).hexdigest()
                        
            # If not already exists in database
            if not episode_in_db(md5key):
                # Add episode to database
                add_episode_to_db(feedID, episode_title, episode_published, episode_url, episode_description, episode_type, md5key)
                newInFeed  += 1
                newInTotal += 1
            entry += 1  # Next entry
            # End of Entry
        # Feedback
        if verbose == True:
            print '%s%s' % (colorize('blue', 'With enclosures:'), colorize('green', enclosure_count))
        print '%s\t%s'   % (colorize('blue', 'New episodes:'),    colorize('number', str(newInFeed)))
        print '%s'       % (colorize('black','-'*30))
    # Go to next feed
    print '%s\t%s'   % (colorize('blue', 'Total new:'),    colorize('number', str(newInTotal)))
########################################################################

# This function is only ment to be run once ############################
# it will mark all episodes as downloaded ##############################
def catchup(feednumber):
    if fake == False:
        sql = 'UPDATE podcast_episodes SET downloaded=1'
        if feednumber != 'all':
            sql += ' WHERE feedID=%s' % feednumber
        cursor.execute(sql)
        connect.commit()
        print '%s %s\n' % (colorize('blue', 'Catched up with feed:'), colorize('green', feednumber))
    else:
        print '%s'                    % (colorize('warning','Fake running: Not altering database.'))
########################################################################

# Colorize the text ####################################################
# Unix specific.
def colorize(colorizeOption = 'error', toColorize = 'Nothing to print.'):
    if colorizeOption == 'green':
        return '\033[0;32m%s\033[0;m'     % toColorize
    elif colorizeOption == 'blue':
        return '\033[0;34m%s\033[0;m'     % toColorize
    elif colorizeOption == 'black':
        return '\033[0;30m%s\033[0;m'     % toColorize
    elif colorizeOption == 'warning':
        return '\033[0;31m%s\033[0;m'     % toColorize
    elif colorizeOption == 'error':
        return '\033[0;31m%s\033[0;m'     % toColorize
    elif colorizeOption == 'number':
        if int(toColorize) != 0:
            return '\033[1;32m%s\033[1;m' % toColorize
        else:
            return '\033[1;31m%s\033[1;m' % toColorize
########################################################################

# Add feed to database #################################################
def add_new_feed(feedURL):
    print colorize('warning','Add feed not implemented yet!')
########################################################################

# Get feedlist #########################################################
def get_feed_list():
    cursor.execute('SELECT feedID, url, title FROM podcast_feeds')
    return cursor.fetchall()
########################################################################

# Add episode to database ##############################################
def add_episode_to_db(feedID, episode_title, episode_published, episode_url, episode_description, episode_type, md5key):
    if fake == False:
        cursor.execute('INSERT INTO podcast_episodes (`feedID`,`title`,`published`,`url`,`description`,`type`,`md5`) VALUES (?, ?, ?, ?, ?, ?, ?)', (feedID, episode_title, episode_published, episode_url, episode_description, episode_type, md5key))
        connect.commit()                                                # Commit to database
    else:
        print '%s'               % (colorize('warning','Fake running: Not altering database.'))
########################################################################

# Test if podcasts already in database #################################
def episode_in_db(md5key):
    cursor.execute('SELECT title FROM podcast_episodes WHERE md5="%s"' % md5key)
    if not cursor.fetchone():
        # Not in db
        return 0
    else:
        # Exists in db
        return 1
########################################################################

# The Main functions job is to deligate work to the other functions ####
def main():
    # parse arguments
    parse_arguments()
    
    if action == 'update':
        update_feeds()
    elif action == 'catchup':
        catchup(feed_to_catchup)
    else:
        usage_screen('error', 'No action specified!')
########################################################################

# Run main() if not called as a module #################################
if __name__ == "__main__":
    print version_string, "\n"                                          # Always print program name first
    main()
########################################################################
